﻿using System;

namespace DotNetCommon.Extensions;

/// <summary>
/// <seealso cref="DateTime"/>的扩展类
/// </summary>
public static class DateTimeExtensions
{
    internal static readonly DateTime Epoch;
    static DateTimeExtensions() => Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

    /// <summary>
    /// 将给定的 <see cref="DateTime"/> 转换为相对 1970-01-01(UTC) 的毫秒数。
    /// </summary>
    /// <remarks>注意: 会先将给定的 DateTime 转为 UTC 格式</remarks>
    public static long ToEpochMilliseconds(this DateTime dateTime) =>
        (long)dateTime.ToUniversalTime().Subtract(Epoch).TotalMilliseconds;

    /// <summary>
    /// 将给定的 <see cref="DateTime"/> 转换为相对 1970-01-01(UTC) 的秒数。
    /// </summary>
    /// <remarks>注意: 会先将给定的 DateTime 转为 UTC 格式</remarks>
    public static long ToEpochSeconds(this DateTime dateTime) =>
        dateTime.ToEpochMilliseconds() / 1000;

    /// <summary>
    /// 检查给定的日期是否在两个提供的日期之间(包含两边界值)
    /// </summary>
    public static bool IsBetween(this DateTime date, DateTime startDate, DateTime endDate) => date >= startDate && date <= endDate;

    /// <summary>
    /// 返回给定日期是否为该月的最后一天
    /// </summary>
    public static bool IsLastDayOfTheMonth(this DateTime dateTime) =>
        dateTime == new DateTime(dateTime.Year, dateTime.Month, 1).AddMonths(1).AddDays(-1);

    /// <summary>
    /// 返回给定日期是否位于周末(周六或周日)
    /// </summary>
    public static bool IsWeekend(this DateTime value) =>
        value.DayOfWeek == DayOfWeek.Sunday || value.DayOfWeek == DayOfWeek.Saturday;

    /// <summary>
    /// 确定给定年份是否为闰年 (谐音,润年)。
    /// </summary>
    public static bool IsLeapYear(this DateTime value) =>
        DateTime.DaysInMonth(value.Year, 2) == 29;

    /// <summary>
    /// 以该时间作为出生日期,计算年龄
    /// </summary>
    public static int Age(this DateTime birthDay)
    {
        var today = DateTime.Today;
        var age = today.Year - birthDay.Year;

        if (birthDay > today.AddYears(-age)) { age--; }
        return age;
    }

    #region 返回格式化字符串

    /// <summary>
    /// 返回"yyyyMMddHHmmss"格式的字符串
    /// </summary>
    public static string ToFileNameString(this DateTime value) => value.ToString("yyyyMMddHHmmss");

    /// <summary>
    /// 返回"yyyyMMddHHmmssfff"格式的字符串
    /// </summary>
    public static string ToFileNameStampString(this DateTime value) => value.ToString("yyyyMMddHHmmssfff");

    /// <summary>
    /// 返回"yyyyMMddHHmmssfff_guid{ext}"格式的字符串<br />
    /// 如: 20210925010203045_5223ed80c21a4facbc30225ed7e061d5.txt （ext参数为: ".txt"）
    /// </summary>
    public static string ToFileNameGuidString(this DateTime value, string ext = "") => $"{value.ToString("yyyyMMddHHmmssfff")}_{Guid.NewGuid().ToString("N")}{ext}";

    #region 不输出时区信息，使用服务器机器时区
    /// <summary>
    /// 返回"yyyy-MM-dd HH:mm:ss"格式的字符串, 如: "2021-02-02 13:45:02"
    /// </summary>
    public static string ToCommonString(this DateTime value) => value.ToString("yyyy-MM-dd HH:mm:ss");

    /// <summary>
    /// 返回"yyyy-MM-dd"格式的字符串, 如: "2021-02-02"
    /// </summary>
    public static string ToCommonDateString(this DateTime value) => value.ToString("yyyy-MM-dd");

    /// <summary>
    /// 返回"HH:mm:ss"格式的字符串, 如: "13:45:02"
    /// </summary>
    public static string ToCommonTimeString(this DateTime value) => value.ToString("HH:mm:ss");

    /// <summary>
    /// 返回"yyyy-MM-dd HH:mm"格式的字符串, 如: "2021-02-02 13:45"
    /// </summary>
    public static string ToCommonMinuteString(this DateTime value) => value.ToString("yyyy-MM-dd HH:mm");

    /// <summary>
    /// 返回"yyyy-MM-dd HH:mm:ss.fff"格式的字符串, 如: "2021-02-02 13:45:02.123"
    /// </summary>
    public static string ToCommonStampString(this DateTime value) => value.ToString("yyyy-MM-dd HH:mm:ss.fff");

    /// <summary>
    /// 返回"yyyy-MM-dd HH:mm:ss.ffffff"格式的字符串, 如: "2021-02-02 13:45:02.123456"
    /// </summary>
    public static string ToCommonStamp2String(this DateTime value) => value.ToString("yyyy-MM-dd HH:mm:ss.ffffff");
    #endregion

    #region 输出时区信息，使用服务器机器时区
    /// <summary>
    /// 返回"yyyy-MM-dd HH:mm zzz"格式的字符串, 如: "2021-02-02 13:45 +08:00"
    /// </summary>
    public static string ToGlobalMinuteString(this DateTime value) => value.ToString("yyyy-MM-dd HH:mm zzz");

    /// <summary>
    /// 返回"yyyy-MM-dd HH:mm:ss.fff zzz"格式的字符串, 如: "2021-02-02 13:45:02.123 +08:00"
    /// </summary>
    public static string ToGlobalStampString(this DateTime value) => value.ToString("yyyy-MM-dd HH:mm:ss.fff zzz");

    /// <summary>
    /// 返回"yyyy-MM-dd HH:mm:ss.fff zzz"格式的字符串, 如: "2021-02-02 13:45:02.123456 +08:00"
    /// </summary>
    public static string ToGlobalStamp2String(this DateTime value) => value.ToString("yyyy-MM-dd HH:mm:ss.ffffff zzz");

    /// <summary>
    /// 返回"yyyy-MM-dd HH:mm:ss zzz"格式的字符串，如: "2021-02-02 13:45:02 +08:00"
    /// </summary>
    public static string ToGlobalString(this DateTime value) => value.ToString("yyyy-MM-dd HH:mm:ss zzz");
    #endregion
    #endregion

    /// <summary>
    /// 返回今天凌晨时间,如: "2022-02-07 20:12:09" => "2022-02-07 00:00:00"
    /// </summary>
    public static DateTime TodayStart(this DateTime dt) => dt.Date;

    /// <summary>
    /// 返回明天凌晨时间,如: "2022-02-07 20:12:09" => "2022-02-08 00:00:00"
    /// </summary>
    public static DateTime TomorrowStart(this DateTime dt) => dt.AddDays(1).Date;
}
